package asteroid

import (
	"fmt"
	"sort"
	"strings"
	"sync"
	"sync/atomic"

	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
)

const (
	DefaultFilter = "*"
	DefaultEvent  = "*"
)

type NodeHandler func(node string)
type FinishHandler func()

type Strategy interface {
	SetNodes(nodes []string)
	Alloc(key string) string
}

type nodeManager struct {
	logger def.Logger
	layer  *Layer
	node   string

	// 除自身外的所有节点
	nodes []string
	// 所有节点
	allNodes []string

	all bool

	reconnectHandler []NodeHandler
	joinHandler      []NodeHandler
	leaveHandler     []NodeHandler
	finishHandler    []FinishHandler

	finished bool

	Strategy
}

func newNodeManager(layer *Layer, logger def.Logger, node string, all bool) *nodeManager {
	return &nodeManager{
		logger:   logger,
		layer:    layer,
		node:     node,
		nodes:    []string{},
		allNodes: []string{node},
		all:      all,

		joinHandler:   []NodeHandler{},
		leaveHandler:  []NodeHandler{},
		finishHandler: []FinishHandler{},
	}
}
func (nm *nodeManager) initNode(layer *Layer, node string) {
	nm.nodes = []string{}
	nm.allNodes = []string{node}
	nm.node = node
	nm.layer = layer
}

func (nm *nodeManager) SetStrategy(strategy Strategy) {
	nm.Strategy = strategy
	nm.setStrategyNodes()
}

// 更新节点信息
func (nm *nodeManager) setStrategyNodes() {
	if nm.Strategy == nil {
		return
	}
	if nm.all {
		if len(nm.layer.exitNodes) > 0 {
			nodes := utils.RemoveDuplicateString(append(nm.allNodes, nm.layer.exitNodes...))
			nm.SetNodes(nodes)
		} else {
			nm.SetNodes(nm.allNodes)
		}
	} else {
		if len(nm.layer.exitNodes) > 0 {
			nodes := utils.RemoveDuplicateString(append(nm.nodes, nm.layer.exitNodes...))
			nm.SetNodes(nodes)
		} else {
			nm.SetNodes(nm.nodes)
		}
	}
}
func (nm *nodeManager) OnJoin(handler NodeHandler) {
	nm.joinHandler = append(nm.joinHandler, handler)
	if len(nm.nodes) > 0 {
		for _, node := range nm.nodes {
			handler(node)
		}
	}
}
func (nm *nodeManager) OnLeave(handler NodeHandler) {
	nm.leaveHandler = append(nm.leaveHandler, handler)
}
func (nm *nodeManager) OnReconnect(handler NodeHandler) {
	nm.reconnectHandler = append(nm.reconnectHandler, handler)
}
func (nm *nodeManager) OnFinish(handler FinishHandler) {
	nm.finishHandler = append(nm.finishHandler, handler)
	//nm.logger.Debugf("Register Finish")
	if nm.finished {
		handler()
	}
}

func (nm *nodeManager) join(node string) {
	nm.finished = false
	if nm.all && nm.node == node {
		// 对于节点为全部节点的应用来说：
		// 已经包含了本节点
		return
	}
	if ok := nm.addNode(node); ok {
		nm.logger.Debugf("Node: join %s", node)
		if err := nm.layer.ConnectNode(node); err != nil {
			nm.logger.Errorf("Node: fail %s", node)
		}

		if nm.joinHandler != nil {
			for key := range nm.joinHandler {
				nm.joinHandler[key](node)
			}
		}
		nm.setStrategyNodes()
	} else {
		if nm.reconnectHandler != nil {
			for key := range nm.reconnectHandler {
				nm.reconnectHandler[key](node)
			}
		}
	}
}
func (nm *nodeManager) leave(node string) {
	nm.finished = false
	if ok := nm.removeNode(node); ok {
		nm.logger.Debugf("Node: leave %s", node)
		if nm.leaveHandler != nil {
			for key := range nm.leaveHandler {
				nm.leaveHandler[key](node)
			}
		}
	}
}

func (nm *nodeManager) finish() {
	if !nm.finished {
		nm.finished = true
	}
	for key := range nm.finishHandler {
		nm.finishHandler[key]()
	}
}

func (nm *nodeManager) ExistNode(node string) bool {
	var result int
	if nm.all {
		result = sort.SearchStrings(nm.allNodes, node)
		//fmt.Println("all", nm.allNodes, node, result)
		if result == 0 && nm.allNodes[0] != node {
			result = -1
		}
	} else {
		result = sort.SearchStrings(nm.nodes, node)
		if result == 0 {
			if len(nm.nodes) == 0 {
				result = -1
			} else if nm.nodes[0] != node {
				result = -1
			}
		}
		//fmt.Println("noall", nm.nodes, node, result)
	}
	if result >= 0 {
		return true
	} else {
		return false
	}
}
func (nm *nodeManager) CurrentNode() string {
	return nm.node
}
func (nm *nodeManager) OtherNodes() []string {
	return nm.nodes
}
func (nm *nodeManager) Count() int {
	return len(nm.nodes)
}
func (nm *nodeManager) AllNode() []string {
	return nm.allNodes
}

func (nm *nodeManager) addNode(node string) bool {
	flag := -1
	for k := range nm.nodes {
		if nm.nodes[k] == node {
			flag = k
			break
		}
	}
	if flag < 0 {
		nm.nodes = append(nm.nodes, node)
		sort.Strings(nm.nodes)
		if nm.all {
			nm.allNodes = append(nm.nodes, nm.node)
			sort.Strings(nm.allNodes)
		} else {
			nm.allNodes = nm.nodes
		}
		nm.setStrategyNodes()
		return true
	}
	return false
}

func (nm *nodeManager) removeNode(node string) bool {
	flag := -1
	for k := range nm.nodes {
		if nm.nodes[k] == node {
			flag = k
			break
		}
	}
	if flag >= 0 {
		l := len(nm.nodes)
		if flag == 0 {
			nm.nodes = nm.nodes[1:]
		} else if flag == l-1 {
			nm.nodes = nm.nodes[0:flag]
		} else {
			nm.nodes = append(nm.nodes[:flag], nm.nodes[flag+1:]...)
		}
		sort.Strings(nm.nodes)
		if nm.all {
			nm.allNodes = append(nm.nodes, nm.node)
			sort.Strings(nm.allNodes)
		} else {
			nm.allNodes = nm.nodes
		}
		nm.setStrategyNodes()
		return true
	}
	return false
}

type memberManager struct {
	id        def.ID
	memberMap sync.Map
	members   int32

	memberJoinHandler  NodeHandler
	memberLeaveHandler NodeHandler
}

func newMemberManager(id def.ID) *memberManager {
	return &memberManager{
		id:        id,
		memberMap: sync.Map{},
		members:   0,
	}
}

func (mm *memberManager) ID() string {
	return mm.id.ID()
}

func (mm *memberManager) clean() {

}
func (mm *memberManager) Members() int {
	return int(mm.members)
}

func (mm *memberManager) close() {
	mm.memberMap.Range(func(key, value interface{}) bool {
		_ = value.(def.Member).Delete(mm)
		return true
	})
}
func (mm *memberManager) Group(category string) bool {
	if category == "room" {
		return true
	}
	if strings.HasPrefix(mm.ID(), category) {
		return true
	}
	return false
}

func (mm *memberManager) Join(member def.Member) error {
	_, ok := mm.memberMap.Load(member.ID())
	if ok {
		return fmt.Errorf("member %s is exists", member.ID())
	}
	mm.memberMap.Store(member.ID(), member)
	atomic.AddInt32(&mm.members, 1)
	if mm.memberJoinHandler != nil {
		mm.memberJoinHandler(member.ID())
	}
	return nil
}

func (mm *memberManager) Remove(member def.Member) error {
	_, ok := mm.memberMap.Load(member.ID())
	if !ok {
		return fmt.Errorf("member %s is not exists", member.ID())
	}
	mm.memberMap.Delete(member.ID())
	atomic.AddInt32(&mm.members, -1)
	if mm.memberLeaveHandler != nil {
		mm.memberLeaveHandler(member.ID())
	}
	return nil
}

func (mm *memberManager) OnMemberJoin(handler NodeHandler) {
	mm.memberJoinHandler = handler
}
func (mm *memberManager) OnMemberLeave(handler NodeHandler) {
	mm.memberLeaveHandler = handler
}

func (mm *memberManager) Find(id string) def.Member {
	member, ok := mm.memberMap.Load(id)
	if ok {
		return member.(def.Member)
	}
	return nil
}

func (mm *memberManager) MemberRange(f func(key interface{}, value interface{}) bool) {
	mm.memberMap.Range(f)
}
